package com.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.session.SessionRepository;
import org.springframework.session.config.SessionRepositoryCustomizer;
import org.springframework.session.data.redis.RedisIndexedSessionRepository;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;
import org.springframework.session.web.http.HeaderHttpSessionIdResolver;

@Configuration
public class SessionConfig  {
//public class SessionConfig implements SessionRepositoryCustomizer {

	/**
	 * 这个配置是可选的，主要用来设置会话id在cookie中如何存储的问题
	 * 关于cookie的domain与path见https://www.jianshu.com/p/1b7aa6fb81ec
	 * 1.domain表示的是cookie所在的域，默认为请求的地址，如网址为www.jb51.net/test/test.aspx，
	 * 那么domain默认为www.jb51.net。
	 * 而跨域访问，如域A为t1.test.com，
	 * 域B为t2.test.com，
	 * 那么在域A生产一个令域A和域B都能访问的cookie就要将该cookie的domain设置为.test.com；如果要在域A生产一个令域A不能访问而域B能访问的cookie就要将该cookie的domain设置为t2.test.com。
	 *
	 * 2.path表示cookie所在的目录，
	 * asp.net默认为/，
	 * 就是根目录。
	 * 在同一个服务器上有目录如下：
	 * /test/,/test/cd/,/test/dd/，
	 * 现设一个cookie1的path为/test/，
	 * cookie2的path为/test/cd/，
	 * 那么test下的所有页面都可以访问到cookie1，
	 * 而/test/和/test/dd/的子页面不能访问cookie2。
	 * 这是因为cookie能让其path路径下的页面访问。
	 *
	 * 3.浏览器会将domain和path都相同的cookie保存在一个文件里，cookie间用*隔开。
	 *
	 * 4.含值键值对的cookie：以前一直用的是nam=value单键值对的cookie，一说到含多个子键值对的就蒙了。现在总算弄清楚了。含多个子键值对的cookie格式是name=key1=value1&key2=value2。可以理解为单键值对的值保存一个自定义的多键值字符串，其中的键值对分割符为&，当然可以自定义一个分隔符，但用asp.net获取时是以&为分割符。
	 *
	 * @return
	 */
/*	@Bean
	public CookieSerializer cookieSerializer(){
		DefaultCookieSerializer defaultCookieSerializer = new DefaultCookieSerializer();
		defaultCookieSerializer.setCookieName("distsessionid");
		//记得域名要与实际一样，这里换成别的域名就会导致cookie失效的
		defaultCookieSerializer.setDomainName("localhost");
		defaultCookieSerializer.setCookiePath("/");

		return defaultCookieSerializer;
	}*/

	/**
	 * 默认的id解析器是CookieHttpSessionIdResolver,见SpringHttpSessionConfiguration
	 * 此类有一个方法setHttpSessionIdResolver可以用来注入一个HttpSessionIdResolver
	 * 所以下面的bean方法就可以更改spring session的id解析机制
	 *
	 * 当注册了一个这样的bean之后，就不会把id写到cookie中了，只把id放到header中
	 * id值就是session.getId的值
	 * @return
	 */
	@Bean
	public HeaderHttpSessionIdResolver headerHttpSessionIdResolver(){
		return new HeaderHttpSessionIdResolver("SESSION-H");
	}

	/**
	 * bean的名字必须是springSessionDefaultRedisSerializer，否则是没有效果的
	 * 这里的设置只会改变value与hash value的序列化器，key与hash key的序列化器仍然是StringRedisSerializer
	 * 这点符合我们的要求。
	 * 这一点是可以在RedisHttpSessionConfiguration类的createRedisTemplate方法看到的
	 *
	 * 如果你想把2个key相关的序列化器也改掉，你只能自己创建RedisTemplate对象，但不能用下面的bean方法sessionRedisOperations
	 * 的形式创建，可以用的方式是实现SessionRepositoryCustomizer接口，在customize方法中进行修改
	 * @return
	 */
	@Bean
	public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
		return new GenericJackson2JsonRedisSerializer();
	}

	/**
	 * 无效的，至少在这个spring boot版本的环境下是无效的
	 *
	 * @return
	 */
	/*@Bean
	public RedisOperations<String, Object> sessionRedisOperations(RedisConnectionFactory redisConnectionFactory) {
		RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
		redisTemplate.setConnectionFactory(redisConnectionFactory);
		redisTemplate.setKeySerializer(new StringRedisSerializer());
		redisTemplate.setHashKeySerializer(new StringRedisSerializer());
		redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
		redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());

		return redisTemplate;
	}*/


	/*@Override
	public void customize(SessionRepository sessionRepository) {
		RedisIndexedSessionRepository repository = (RedisIndexedSessionRepository) sessionRepository;
		RedisTemplate<Object, Object> redisTemplate = (RedisTemplate<Object, Object>) repository.getSessionRedisOperations();
		redisTemplate.setKeySerializer(new StringRedisSerializer());
		redisTemplate.setHashKeySerializer(new StringRedisSerializer());
		redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
		redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
	}*/
}